/*
    Ship Module, Handles the Ship Object
*/
#ifndef SHIP
#define SHIP

#include "Class Manager.h"
#include "Dark.h"
#include "Projectile.h"
#include "Ship Type.h"
#include "Weapon.h"

class Ship
{
    public :

        Ship
        (
            int
        )
        {
        }
        void Init
        (
            ShipType   *iPShipType,
            double      iXLoc,
            double      iYLoc,
            double      iXVelocity,
            double      iYVelocity,
            double      iRotation,
            int         iColor,
            int         iPowerOrbXLoc
        )
        {
            _pShipType     =   iPShipType;
            _location.set(iXLoc,iYLoc);
            _xVelocity    =   iXVelocity;
            _yVelocity    =   iYVelocity;
            _friction     =   iPShipType->_friction;
            _rotation     =   iRotation;
            _rotationRate =   iPShipType->_rotationRate;
            _mass         =   iPShipType->_mass;
            _acceleration =   iPShipType->_thrust / iPShipType->_mass;
            _energy       =
            _energyCap    =   iPShipType->_energyCap;
            _energyGen    =   iPShipType->_energyGen;
            _hull         =   
            _hullCap      =   iPShipType->_hullCap;
            _radius       =   iPShipType->_radius;
            _color        =   iColor;
            _pImage       =   iPShipType->_pImage;
            _pShieldImage =   iPShipType->_pShieldImage;
            
            _powerOrbSpriteId = Dark::GetFreeSpriteId();
            dbSprite(_powerOrbSpriteId,iPowerOrbXLoc,Dark::SIZE_Y,4);
            dbSetSpriteDiffuse(_powerOrbSpriteId,dbRGBR(iColor),dbRGBG(iColor),dbRGBB(iColor));
            //dbOffsetSprite(_powerOrbSpriteId,0,32);
            dbSizeSprite  (_powerOrbSpriteId,32,32);
            
            _spriteId     = Dark::GetFreeSpriteId();
            dbCreateAnimatedSprite(_spriteId,const_cast< char* > (_pImage->image_location().c_str()),3,3,_pImage->image_id());
            dbSprite(_spriteId, iXLoc, iYLoc,_pImage->image_id());
            dbSetSpriteFrame(_spriteId,_pImage->image_id());
            dbSetSpriteDiffuse(_spriteId,dbRGBR(iColor),dbRGBG(iColor),dbRGBB(iColor));
            dbOffsetSprite(_spriteId,_radius,_radius);
            dbSizeSprite(_spriteId,_radius*2,_radius*2);
            
            _shieldSpriteId = Dark::GetFreeSpriteId();
            dbSprite(_shieldSpriteId, iXLoc, iYLoc,_pShieldImage->image_id());
            dbSetSpriteDiffuse(_shieldSpriteId,dbRGBR(iColor),dbRGBG(iColor),dbRGBB(iColor));
            dbOffsetSprite(_shieldSpriteId,_radius,_radius);
            dbSizeSprite(_shieldSpriteId,_radius*2,_radius*2);
            
            _thrustForward  = false;
            _thrustBackward = false;
            _turnLeft       = false;
            _turnRight      = false;
            _shoot          = false;
        }

        ~Ship
        (
            void
        )
        {
            dbDeleteSprite(_spriteId);
            dbDeleteSprite(_powerOrbSpriteId);
        }
        
        bool addWeapon
        (
            WeaponType *iPWeaponType,
            double iXOrigin,
            double iYOrigin,
            double iRotation
            
        )
        {
            _pWeaponList.push_front(new Weapon(iPWeaponType,iXOrigin,iYOrigin,iRotation));
            return true; // will return false later, as it will have to validate avalible room in/for modules.
        }
        
        bool refresh
        (
            void
        )
        {
/*
    The 3x3 Ship Sprite has all the thrusting animations for the ship, which has the default at the 5 position,
    Thrust forward at the 2, etc...
*/
            int animation = 5; 
            if (_thrustForward && !_thrustBackward)
            {
                _xVelocity += _acceleration * dbCos(_rotation);
                _yVelocity += _acceleration * dbSin(_rotation);
                animation -= 3;
            }
            else if (_thrustBackward)
            {
                _xVelocity -= _acceleration * dbCos(_rotation) * 0.5; // Half reverse thrust
                _yVelocity -= _acceleration * dbSin(_rotation) * 0.5;
                animation += 3;
            }
            if (_turnLeft && !_turnRight)
            {
                _rotation -= _rotationRate;
                animation -= 1;
            }
            else if (_turnRight)
            {
                _rotation += _rotationRate;
                animation += 1;
            }
            {
                list<Weapon*>::iterator it = _pWeaponList.begin();
                while(it != _pWeaponList.end())
                {
                    (*it)->Refresh(_energy);
                    it++;
                }
            }
            if (_shoot)
            {
                list<Weapon*>::iterator it = _pWeaponList.begin();
                while(it != _pWeaponList.end())
                {
                    (*it)->Shoot(this,&_location,_rotation,_xVelocity,_yVelocity);
                    it++;
                }
            }
            
            BJ_gX = 0;
            BJ_gY = 0;
            BJ_gR = _radius;
            BJ_gD = 0;
            BJ_gTempLoc = &_location;
            BJ_TEMP_SHIP = this;
            ProjectileManager.for_each(ProjectileInRange);
            _xVelocity += BJ_gX/_mass;
            _yVelocity += BJ_gY/_mass;
            _hull      -= BJ_gD;// More complex damage equations later...
            
            dbSetSpriteAlpha(_shieldSpriteId, 0+(175*(_hull/_hullCap)));
            if (_hull <= 0)
            {
                _location.set(Dark::SIZE_X*BJ_rand(0.1,0.9),Dark::SIZE_Y*BJ_rand(0.1,0.9));
                _rotation = 0;
                _energy = _energyCap;
                _hull = _hullCap;
            }
            
            
            _location.set(_location.x()+_xVelocity * Dark::PERIOD,_location.y()+_yVelocity * Dark::PERIOD);
            if (!(_location.in_bounds(0,Dark::SIZE_X,0,Dark::SIZE_Y,_radius)))
            {
                _location.set(Dark::SIZE_X/2,Dark::SIZE_Y/2);
            }
            
            _xVelocity *= _friction;
            _yVelocity *= _friction;
            _energy = BJ_min(_energy + _energyGen,_energyCap);
            dbSetSpriteAlpha(_powerOrbSpriteId ,255.0+((  0.0/_energyCap)*_energy));
            dbSizeSprite  (_powerOrbSpriteId,32, 32.0+((  0.0/_energyCap)*_energy));
            dbOffsetSprite(_powerOrbSpriteId,16,  4.0+(( 28.0/_energyCap)*_energy));
            
            dbSprite(_spriteId, _location.x(), _location.y(),_pImage->image_id());
            dbSprite(_shieldSpriteId, _location.x(), _location.y(),_pShieldImage->image_id());
            dbSetSpriteFrame(_spriteId,animation);
            dbRotateSprite(_spriteId,_rotation+90);
            return false;
        }
        void ThrustForward
        (
            bool Flag
        )
        {
            _thrustForward = Flag;
        }
        void ThrustBackward
        (
            bool Flag
        )
        {
            _thrustBackward = Flag;
        }
        void TurnLeft
        (
            bool Flag
        )
        {
            _turnLeft = Flag;
        }
        void TurnRight
        (
            bool Flag
        )
        {
            _turnRight = Flag;
        }
        void Shoot
        (
            bool Flag
        )
        {
            _shoot = Flag;
        }
    private:
        ShipType  *_pShipType      ;
        DarkImage *_pImage         ;
        DarkImage *_pShieldImage   ;
        list<Weapon*> _pWeaponList ;
        int       _spriteId        ;
        int       _shieldSpriteId  ;
        int       _powerOrbSpriteId; // Make this part of the UI class
        Point     _location        ;
        double    _xVelocity       ;
        double    _yVelocity       ;
        double    _acceleration    ;
        double    _friction        ;
        double    _rotation        ;
        double    _rotationRate    ;
        double    _energy          ;
        double    _energyGen       ;
        double    _energyCap       ;
        double    _hull            ;
        double    _hullCap         ;
        int       _color           ;
        double    _radius          ;
        double    _mass            ;
        bool      _thrustForward   ;
        bool      _thrustBackward  ;
        bool      _turnLeft        ;
        bool      _turnRight       ;
        bool      _shoot           ;
};
ObjectManager<Ship> ShipManager;

#endif